#pragma once
#include <iostream>
#include <memory>
#include <unistd.h>
#include "Socket.hpp"
#include <sys/epoll.h>
#include"common.hpp"
using namespace LogMoudle;
using namespace SocketMoudle;
class EpollServer
{
    const static int defaultd = -1;
    const static int size = 64;

public:
    EpollServer(uint16_t port)
        : _listensock(std::make_unique<TcpSocket>()), _isrunning(false),_epfd(defaultd)
    {
        _listensock->BuildTcpSocketMethod(port);
        _epfd=epoll_create(256);
        if(_epfd<0)
        {
             LOG(loglevel::FATAL) << "epoll_create error";
            exit(EPOLL_CREATE_ERR);
        }
        LOG(loglevel::INFO) << "epoll_create success: " << _epfd; // 4
        struct epoll_event ev;
        ev.events=EPOLLIN;
        ev.data.fd=_listensock->Fd();
        int n=epoll_ctl(_epfd,EPOLL_CTL_ADD,_listensock->Fd(),&ev);
        if (n < 0)
        {
            LOG(loglevel::FATAL) << "add listensockfd failed";
            exit(EPOLL_CTL_ERR);
        }
    }
    void Start()
    {
        int timeout = -1;
        _isrunning = true;
        while (_isrunning)
        {
             int n=epoll_wait(_epfd,_revs,size,timeout);
            switch (n)
            {
            case -1:
                LOG(loglevel::ERROR) << "epoll error";
                break;
            case 0:
                LOG(loglevel::DEBUG) << "time out...";
                break;
            default:
                // 有事件就绪,就不仅仅是新连接到来了吧？读事件就绪啊？
                LOG(loglevel::DEBUG) << "有事件就绪了..., n : " << n;
                Dispatcher(n); // 处理就绪的事件
                break;
            }
        }
        _isrunning = false;
    }
    void Dispatcher(int rnum)
    {
         LOG(loglevel::DEBUG) << "event ready ..."; // LT: 水平触发模式--epoll默认
        for (int i = 0; i < rnum; i++)
        {
             // epoll也要循环处理就绪事件--这是应该的，本来就有可能有多个fd就绪！
             int sockfd=_revs[i].data.fd;
             uint32_t revent=_revs[i].events;
              // 读事件就绪
             if(revent&EPOLLIN)
             {
                if(sockfd==_listensock->Fd())
                {
                    Acceptr();

                }
                else{
                    Recver(sockfd);
                }
             }
        }
    }
    void Acceptr()//获取连接
    {
        InetAddr client;
        int fd = _listensock->Accept(&client);
        if (fd >= 0)
        {
            LOG(loglevel::INFO) << "get a new link, sockfd: "
                                << fd << ", client is: " << client.StringAddr();
            struct epoll_event ev;
            ev.events=EPOLLIN;
            ev.data.fd=fd;
            int n=epoll_ctl(_epfd,EPOLL_CTL_ADD,fd,&ev);//将新的fd插入到系统的红黑树中
            if(n<0)
            {
                 LOG(loglevel::WARNING) << "add listensockfd failed";
            }
            else{
                 LOG(loglevel::INFO) << "epoll_ctl add sockfd success: "<< fd;
            }
        }
    }
    void Recver(int sockfd) // 普通读取
    {
        char buffer[1024];
        ssize_t n = recv(sockfd, buffer, sizeof(buffer)-1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << "client say@ " << buffer << std::endl;
        }
        else if (n == 0)
        {
            LOG(loglevel::INFO) << "clien quit...";
            int ret=epoll_ctl(_epfd,EPOLL_CTL_DEL,sockfd,nullptr);
            if(ret>0)
            {
                 LOG(loglevel::INFO) << "epoll_ctl remove sockfd success: " << sockfd;
            }
            close(sockfd);

        }
        else
        {
            LOG(loglevel::INFO) << "recv error";
            int ret=epoll_ctl(_epfd,EPOLL_CTL_DEL,sockfd,nullptr);
            if(ret>0)
            {
                 LOG(loglevel::INFO) << "epoll_ctl remove sockfd success: " << sockfd;
            }
            close(sockfd);
        }
    }
    void Stop()
    {
        _isrunning = false;
    }
    ~EpollServer()
    {
         _listensock->Close();
        if (_epfd > 0)
            close(_epfd);
    }

private:
    bool _isrunning;
    std::unique_ptr<Socket> _listensock;
    int _epfd;
    struct epoll_event _revs[size];
};